//@author A0083782W
//This file has a UCTimeHandler, which literally means "UserCommand class helper"
//It uses a few class that will help to understand if a string is a date or time
//is here.
//And to do so, we needs loads of loads of loads of constants,
//Therefore I put it outside the main classes, and give it a namespace to encapsulate the
//constants, so that it will not affect your program.
//Therefore, again in theory, no other class should ever access this file.
//However, if there is really a need, feel free to do it :-)
//I will explain a bit of what is going on here.
//When a string message is sent to the UserCommand class, it will be split into words
//and analysed in the context.
//The AWord class is therefore needed to store a word.  It is also given the capability of
//froming a doubly and head to tail linkedlist. Each AWord object is not only able to store 
//information, but also to communicate with its fellows, realising who they are.
//The WordList class is able to form the linklist using AWord, ask them to co-ordinate and 
//choose the most valuabe member.
//
//Some other common functions are here as well. Functions to tell if a string is a time , day or
//month, etc. 
//All string constant list is here. Changing this list and the respective _N constants will make 
//the program able to adjust. So it is quite resilient.
//
//NOTE: AWords class is designed is such a fashion that no other class than WordList can use it
//If not, error will occur.

#pragma once

#include <string>
#include <vector>
#include "Settings.h"
#include "EventTime.h"
#include "ThrowErrorCode.h"
#include "OperationType.h"

using std::string;
using std::vector;
using CommonDataType::pos_int;
using CommonDataType::con_chr;
using CommonDataType::con_str;
using CommonDataType::ByteInt;
using namespace StringManipulator;
using namespace TimeConstants;
using TimeManipulator::getMaxDay;

namespace UCTimeHandler {		
	class AWord {
	public:
		AWord* getNext() const;
		AWord* getPrev() const;
		void setNext(AWord* const next);
		void setPrev(AWord* const prev);
		NodeType getType() const;
		AWord (con_str& Word, const pos_int wordIndex, const bool * throwable);
		void setType(const NodeType newType);
		AWord& operator^ (const int arrayIndex) const;
		pos_int getIndex() const;
		string getWord() const;
		Nature getNature() const;
		void setNature(Nature newNature);
		void meditate();
		void makeOClockFriends();
		void makeMonthFriends();
		void makeForcedFriends();
		void makeWeekFriends();
		void makeTMRFriends();
		void makeTodayFriends();
		void makeDurationFriends(string& date1, string&time1, string&date2, string& time2);
		void findPartner();
		bool const * _throwable;

	private:
		string _word;
		pos_int _index;
		AWord *_prev;
		AWord *_next;
		NodeType _myType;
		Nature _myNature;
	};
	
	class WordList {
	public:
		pos_int getSize() const;
		void solveAll();
		WordList(con_str& mainString);
		WordList();
		void setMessage(con_str& mainString);
		~WordList();
		AWord& operator[] (const pos_int postion) const;
		void setThrowable(const bool newValue);

		//Will NOT empty the current stack
		void callChildren(Nature specificNature);
		
		flexiReturnPtr getTimeString() const;
		flexiReturnPtr getDateString() const;
		bool isTimeStringDuration() const;
		bool isDateStringDuration() const;
		AWord* getHead();
		REPEAT_RULE getRepeatRule();
		void reset();
		void getStartEndTimer (Time& startTime, Time& endTime);

	private:
		string messageString;
		pos_int _nNum;
		AWord* _head;
		AWord* _tail;
		string _timeString[DURATION_MEMBER];
		string _dateString[DURATION_MEMBER];
		REPEAT_RULE _repeatRule;
		bool _isDateDuration;
		bool _isTimeDuration;
		bool _throwable;
		vector<AWord*> currentStack;

		void negotiate(Nature calledNature);
		void solveTime();
		void solveDate();
		void solveDirectDuration();
		void solveComplexDuration();
		void solveRepeat();
		void removeDying();
		void delNode( AWord* node);
	};

	//These functions tell the user what type of string is the input mainString
	//They do not ignore case. if you intend them to ignore, pls use the ignoreCase function
	bool isWeekday (con_str& mainString);
	bool isDate (con_str& mainString, con_chr dateSepChar[], const pos_int dateSepCharSize);
	bool isTime (con_str& mainString);
	bool isMonth (con_str& mainString);
	bool isAM_PM (con_str& mainString);
	bool isMorning (con_str& mainString);
	bool isAfternoon (con_str& mainString);
	bool isToday (con_str& mainString);
	bool isTmr (con_str& mainString);
	bool isPrep (con_str& mainString);
	bool isOClock (con_str& mainString);
	bool isTimeDuration (con_str& mainString);
	bool isDateDuration (con_str& mainString);
	bool isWordTo (con_str& mainString);
	bool isDurationChar (con_str& mainString);
	bool isNext (con_str& mainString);
	bool isThis (con_str& mainString);
	bool isComing (con_str& mainString);
	bool isEvery (con_str& mainString);
	bool isEveryDay (con_str& mainString);
	bool isWordWeek (con_str& mainString);
	bool isWordDay (con_str& mainString);
	bool isWordMonth (con_str& mainString);
	bool isWordMonthly (con_str& mainString);
	bool isWordWeekly (con_str& mainString);
	Month getMonth (con_str& mainString);
	WeekDay getDayOfWeek (con_str& mainString);

	void goToNextWeek(Time& timer);
	bool readToTime (con_str& mainString, Time& timer);
	bool readToDate (con_str& mainString, Time& timer);

	//detect if mainString is in the format of "XX:XX"
	bool isStandardTime (con_str& mainString, bool isAMPM);

};